package service

import (
	"bolt-manager/model"
	bolt "go.etcd.io/bbolt"
)

var dbMap = make(map[string]*bolt.DB) // bolt连接缓存

// key类型，存储桶：false，键值对：true
type KeyType struct {
	Name string `json:"name"`
	Leaf bool   `json:"leaf"`
}

// 存储桶tree
type BucketTree struct {
	Name     string       `json:"name"`
	Children []BucketTree `json:"children"`
}

// keys分页数据
type KeysPage struct {
	Total int      `json:"total"`
	Rows  []string `json:"rows"`
}

// 开启数据库
func openDb(dbName string) *bolt.DB {
	if dbMap[dbName] == nil {
		// 开启数据库
		db, err := bolt.Open(dbName, 0600, nil)
		if err != nil {
			panic(model.NewErrorMessage("数据库开启失败"))
		}
		dbMap[dbName] = db
	}
	return dbMap[dbName]
}

// 查询存储桶树形结构
func QueryBucketTree(dbName string) []BucketTree {
	bucketTree := make([]BucketTree, 0)
	db := openDb(dbName)
	_ = db.View(func(tx *bolt.Tx) error {
		tx.ForEach(func(name []byte, b *bolt.Bucket) error {
			bucketTree = append(bucketTree, BucketTree{string(name), recursionBucketTree(b)})
			return nil
		})
		return nil
	})
	return bucketTree
}

// 存储桶递归
func recursionBucketTree(b *bolt.Bucket) []BucketTree {
	children := make([]BucketTree, 0)
	b.ForEach(func(k, v []byte) error {
		if v == nil {
			children = append(children, BucketTree{string(k), recursionBucketTree(b.Bucket(k))})
		}
		return nil
	})
	return children
}

// 分页查询存储桶keys
func QueryBucketKeys(dbName string, bucketLink []string, current, size int) KeysPage {
	if len(bucketLink) == 0 {
		panic(model.NewErrorMessage("未选择存储桶"))
	}
	result := KeysPage{}
	keys := make([]string, 0)
	total := 0
	offset := (current-1) * size
	db := openDb(dbName)
	_ = db.View(func(tx *bolt.Tx) error {
		var bucket *bolt.Bucket
		for i := range bucketLink {
			// 特殊处理顶层存储桶
			if i == 0 {
				bucket = tx.Bucket([]byte(bucketLink[i]))
			} else {
				bucket = bucket.Bucket([]byte(bucketLink[i]))
			}
			if bucket == nil {
				panic(model.NewErrorMessage("存储桶不存在：" + bucketLink[i]))
			}
			// 最后一层
			if i == len(bucketLink)-1 {
				// 添加所有key
				bucket.ForEach(func(k, v []byte) error {
					if v != nil {
						total++
						if size > 0 && total > offset {
							size--
							keys = append(keys, string(k))
						}
					}
					return nil
				})
			}
		}
		return nil
	})
	result.Rows = keys
	result.Total = total
	return result
}

// 查询指定key的数据
func QueryKeyValue(dbName string, bucketLink []string, key string) string {
	if len(bucketLink) == 0 {
		panic(model.NewErrorMessage("未选择存储桶"))
	}
	if key == "" {
		panic(model.NewErrorMessage("未选择key"))
	}
	var value string
	db := openDb(dbName)
	_ = db.View(func(tx *bolt.Tx) error {
		var bucket *bolt.Bucket
		for i := range bucketLink {
			// 特殊处理顶层存储桶
			if i == 0 {
				bucket = tx.Bucket([]byte(bucketLink[i]))
			} else {
				bucket = bucket.Bucket([]byte(bucketLink[i]))
			}
			if bucket == nil {
				panic(model.NewErrorMessage("存储桶不存在：" + bucketLink[i]))
			}
			// 最后一层
			if i == len(bucketLink)-1 {
				// 查询指定key
				valueByte := bucket.Get([]byte(key))
				if valueByte == nil {
					panic(model.NewErrorMessage("key不存在：" + key))
				}
				value = string(valueByte)
			}
		}
		return nil
	})
	return value
}

// 添加存储桶
func AddBucket(dbName string, bucketLink []string, key string) {
	if key == "" {
		panic(model.NewErrorMessage("未填写key"))
	}
	db := openDb(dbName)
	_ = db.Update(func(tx *bolt.Tx) error {
		// 没有元素，说明添加顶层存储桶
		if len(bucketLink) == 0 {
			// 添加存储桶
			_, err := tx.CreateBucket([]byte(key))
			if err != nil {
				panic(model.NewErrorMessage("存储桶添加失败：" + err.Error()))
			}
			return nil
		}
		var bucket *bolt.Bucket
		for i := range bucketLink {
			// 特殊处理顶层存储桶
			if i == 0 {
				bucket = tx.Bucket([]byte(bucketLink[i]))
			} else {
				bucket = bucket.Bucket([]byte(bucketLink[i]))
			}
			if bucket == nil {
				panic(model.NewErrorMessage("存储桶不存在：" + bucketLink[i]))
			}
			// 最后一层
			if i == len(bucketLink)-1 {
				// 添加存储桶
				_, err := bucket.CreateBucket([]byte(key))
				if err != nil {
					panic(model.NewErrorMessage("存储桶添加失败：" + err.Error()))
				}
			}
		}
		return nil
	})
}

// 删除存储桶
func DeleteBucket(dbName string, bucketLink []string) {
	if len(bucketLink) == 0 {
		panic(model.NewErrorMessage("未选择存储桶"))
	}
	db := openDb(dbName)
	_ = db.Update(func(tx *bolt.Tx) error {
		// 只有1个元素，说明是顶层存储桶
		if len(bucketLink) == 1 {
			// 删除存储桶
			err := tx.DeleteBucket([]byte(bucketLink[0]))
			if err != nil {
				panic(model.NewErrorMessage("存储桶删除失败：" + err.Error()))
			}
			return nil
		}
		var bucket *bolt.Bucket
		for i := range bucketLink {
			// 特殊处理顶层存储桶
			if i == 0 {
				bucket = tx.Bucket([]byte(bucketLink[i]))
			} else {
				bucket = bucket.Bucket([]byte(bucketLink[i]))
			}
			if bucket == nil {
				panic(model.NewErrorMessage("存储桶不存在：" + bucketLink[i]))
			}
			// 倒数第二层
			if i == len(bucketLink)-2 {
				// 删除存储桶
				err := bucket.DeleteBucket([]byte(bucketLink[i+1]))
				if err != nil {
					panic(model.NewErrorMessage("存储桶删除失败：" + err.Error()))
				}
				return nil
			}
		}
		return nil
	})
}

// 更新键值对
func UpdateBucketKey(dbName string, bucketLink []string, key string, value string, isNew bool) {
	if len(bucketLink) == 0 {
		panic(model.NewErrorMessage("未选择存储桶"))
	}
	if key == "" {
		panic(model.NewErrorMessage("未填写key"))
	}
	db := openDb(dbName)
	_ = db.Update(func(tx *bolt.Tx) error {
		var bucket *bolt.Bucket
		for i := range bucketLink {
			// 特殊处理顶层存储桶
			if i == 0 {
				bucket = tx.Bucket([]byte(bucketLink[i]))
			} else {
				bucket = bucket.Bucket([]byte(bucketLink[i]))
			}
			if bucket == nil {
				panic(model.NewErrorMessage("存储桶不存在：" + bucketLink[i]))
			}
			// 最后一层
			if i == len(bucketLink)-1 {
				// 判断键值对是否已存在
				if isNew {
					oldValue := bucket.Get([]byte(key))
					if oldValue != nil {
						panic(model.NewErrorMessage("键值对已存在"))
					}
				}
				// 更新键值对
				err := bucket.Put([]byte(key), []byte(value))
				if err != nil {
					panic(model.NewErrorMessage("键值对更新失败：" + err.Error()))
				}
			}
		}
		return nil
	})
}

// 删除键值对
func DeleteBucketKey(dbName string, bucketLink []string, key string) {
	if len(bucketLink) == 0 {
		panic(model.NewErrorMessage("未选择存储桶"))
	}
	if key == "" {
		panic(model.NewErrorMessage("未选择key"))
	}
	db := openDb(dbName)
	_ = db.Update(func(tx *bolt.Tx) error {
		var bucket *bolt.Bucket
		for i := range bucketLink {
			// 特殊处理顶层存储桶
			if i == 0 {
				bucket = tx.Bucket([]byte(bucketLink[i]))
			} else {
				bucket = bucket.Bucket([]byte(bucketLink[i]))
			}
			if bucket == nil {
				panic(model.NewErrorMessage("存储桶不存在：" + bucketLink[i]))
			}
			// 最后一层
			if i == len(bucketLink)-1 {
				// 删除键值对
				err := bucket.Delete([]byte(key))
				if err != nil {
					panic(model.NewErrorMessage("键值对删除失败：" + err.Error()))
				}
			}
		}
		return nil
	})
}
